package com.jzo2o.orders.manager.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.market.CouponApi;
import com.jzo2o.api.market.dto.request.CouponUseBackReqDTO;
import com.jzo2o.api.orders.dto.request.OrderCancelReqDTO;
import com.jzo2o.api.orders.dto.response.OrderResDTO;
import com.jzo2o.api.orders.dto.response.OrderSimpleResDTO;
import com.jzo2o.api.trade.enums.RefundStatusEnum;
import com.jzo2o.common.constants.UserType;
import com.jzo2o.common.enums.EnableStatusEnum;
import com.jzo2o.common.expcetions.CommonException;
import com.jzo2o.common.model.CurrentUserInfo;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.JsonUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.mvc.utils.UserContext;
import com.jzo2o.orders.base.config.OrderStateMachine;
import com.jzo2o.orders.base.constants.RedisConstants;
import com.jzo2o.orders.base.enums.OrderPayStatusEnum;
import com.jzo2o.orders.base.enums.OrderStatusChangeEventEnum;
import com.jzo2o.orders.base.enums.OrderStatusEnum;
import com.jzo2o.orders.base.mapper.OrdersCanceledMapper;
import com.jzo2o.orders.base.mapper.OrdersMapper;
import com.jzo2o.orders.base.model.domain.Orders;
import com.jzo2o.orders.base.model.domain.OrdersCanceled;
import com.jzo2o.orders.base.model.domain.OrdersRefund;
import com.jzo2o.orders.base.model.dto.OrderSnapshotDTO;
import com.jzo2o.orders.base.service.IOrdersCommonService;
import com.jzo2o.orders.manager.handler.OrdersHandler;
import com.jzo2o.orders.manager.model.dto.OrderCancelDTO;
import com.jzo2o.orders.manager.model.dto.request.OrderPageQueryReqDTO;
import com.jzo2o.orders.manager.model.dto.response.OperationOrdersDetailResDTO;
import com.jzo2o.orders.manager.model.dto.response.OrdersPayResDTO;
import com.jzo2o.orders.manager.service.IOrdersCreateService;
import com.jzo2o.orders.manager.service.IOrdersManagerService;
import com.jzo2o.orders.manager.service.IOrdersRefundService;
import com.jzo2o.redis.helper.CacheHelper;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

import static com.jzo2o.orders.base.constants.FieldConstants.SORT_BY;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author itcast
 * @since 2023-07-10
 */
@Slf4j
@Service
public class OrdersManagerServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements IOrdersManagerService {

    @Resource
    private IOrdersManagerService owner;
    @Resource
    private OrdersCanceledMapper ordersCanceledMapper;
    @Resource
    private IOrdersCommonService ordersCommonService;
    @Resource
    private IOrdersCreateService ordersCreateService;
    @Resource
    private IOrdersRefundService ordersRefundService;
    @Resource
    public OrdersHandler ordersHandler;
    @Resource
    public OrderStateMachine orderStateMachine;
    @Resource
    public CacheHelper cacheHelper;
    @Resource
    private CouponApi couponApi;

    @Override
    public List<Orders> batchQuery(List<Long> ids) {
        LambdaQueryWrapper<Orders> queryWrapper = Wrappers.<Orders>lambdaQuery().in(Orders::getId, ids).ge(Orders::getUserId, 0);
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public Orders queryById(Long id) {
        return baseMapper.selectById(id);
    }

    /**
     * 滚动分页查询
     *
     * @param currentUserId 当前用户id
     * @param ordersStatus  订单状态，0：待支付，100：派单中，200：待服务，300：服务中，400：待评价，500：订单完成，600：已取消，700：已关闭
     * @param sortBy        排序字段
     * @return 订单列表
     */
    @Override
    public List<OrderSimpleResDTO> consumerQueryList(Long currentUserId, Integer ordersStatus, Long sortBy) {
        // 1.构件查询条件
        LambdaQueryWrapper<Orders> queryWrapper = Wrappers.<Orders>lambdaQuery()
                .select(Orders::getId)
                .eq(Orders::getUserId, currentUserId)
                .eq(Orders::getDisplay, EnableStatusEnum.ENABLE.getStatus())
                .eq(ObjectUtils.isNotNull(ordersStatus), Orders::getOrdersStatus, ordersStatus)
                .lt(ObjectUtils.isNotNull(sortBy), Orders::getSortBy, sortBy);
        Page<Orders> queryPage = new Page<>();
        queryPage.addOrder(OrderItem.desc(SORT_BY));
        queryPage.setSearchCount(false);

        // 2.查询订单id列表
        Page<Orders> ordersPage = baseMapper.selectPage(queryPage, queryWrapper);
        if (ObjectUtil.isEmpty(ordersPage.getRecords())) {
            return new ArrayList<>();
        }
        // 提取订单id列表
        List<Long> orderIds = CollUtils.getFieldValues(ordersPage.getRecords(), Orders::getId);
        String redisKey = String.format(RedisConstants.RedisKey.ORDERS, currentUserId);
        return cacheHelper.batchGet(redisKey,
                orderIds,
                (noCacheObjectIds, clazz) -> {
                    if (ObjectUtils.isEmpty(noCacheObjectIds)) {
                        return new HashMap<>();
                    }
                    return this.batchQuery(noCacheObjectIds).stream()
                            .collect(Collectors.toMap(Orders::getId, o -> BeanUtils.toBean(o, OrderSimpleResDTO.class)));
                }
                , OrderSimpleResDTO.class, 600L);
    }

    /**
     * 根据订单id查询
     *
     * @param id 订单id
     * @return 订单详情
     */
    @Override
    public OrderResDTO getDetail(Long id) {
        // 通过状态机获取快照缓存
        String orderSnapshotJson = orderStateMachine.getCurrentSnapshotCache(id.toString());
        OrderSnapshotDTO orderSnapshotDTO = JsonUtils.toBean(orderSnapshotJson, OrderSnapshotDTO.class);
        orderSnapshotDTO = canalIfPayOvertime(orderSnapshotDTO);
        OrdersCanceled ordersCanceled = ordersCanceledMapper.selectById(orderSnapshotDTO.getId());
        OrderResDTO orderResDTO = BeanUtil.toBean(orderSnapshotDTO, OrderResDTO.class);
        if (ObjectUtils.equal(orderResDTO.getOrdersStatus(), OrderStatusEnum.CANCELED.getStatus())) {
            BeanUtils.copyProperties(ordersCanceled, orderResDTO);
        }
        return orderResDTO;
    }

    // 如果超时更新订单状态
    public OrderSnapshotDTO canalIfPayOvertime(OrderSnapshotDTO orderSnapshotDTO) {
        if (ObjectUtils.equal(orderSnapshotDTO.getOrdersStatus(), OrderStatusEnum.NO_PAY.getStatus())
                && orderSnapshotDTO.getCreateTime().isBefore(LocalDateTime.now().minusMinutes(15))) {
            OrdersPayResDTO ordersPayResDTO = ordersCreateService.getPayResultFromTradServer(orderSnapshotDTO.getId());
            if (ObjectUtils.notEqual(ordersPayResDTO.getPayStatus(), OrderPayStatusEnum.PAY_SUCCESS.getStatus())) {
                OrderCancelDTO orderCancelDTO = new OrderCancelDTO();
                orderCancelDTO.setId(orderSnapshotDTO.getId());
                orderCancelDTO.setCurrentUserName("SYSTEM");
                orderCancelDTO.setCurrentUserType(UserType.SYSTEM);
                orderCancelDTO.setCancelReason("订单超时,自动取消");
                owner.cancelByNoPay(orderCancelDTO);
            }
            // 从快照中读取新更新的订单状态
            String orderSnapshotJson = orderStateMachine.getCurrentSnapshotCache(orderSnapshotDTO.getId().toString());
            orderSnapshotDTO = JsonUtils.toBean(orderSnapshotJson, OrderSnapshotDTO.class);
        }
        return orderSnapshotDTO;
    }

    /**
     * 订单评价
     *
     * @param ordersId 订单id
     */
    @Override
    @Transactional
    public void evaluationOrder(Long ordersId) {
//        //查询订单详情
//        Orders orders = queryById(ordersId);
//
//        //构建订单快照
//        OrderSnapshotDTO orderSnapshotDTO = OrderSnapshotDTO.builder()
//                .evaluationTime(LocalDateTime.now())
//                .build();
//
//        //订单状态变更
//        orderStateMachine.changeStatus(orders.getUserId(), orders.getId().toString(), OrderStatusChangeEventEnum.EVALUATE, orderSnapshotDTO);
    }


    @Override
    public void cancel(OrderCancelReqDTO orderCancelReqDTO) {
        OrderCancelDTO orderCancelDTO = BeanUtils.toBean(orderCancelReqDTO, OrderCancelDTO.class);
        CurrentUserInfo currentUserInfo = UserContext.currentUser();
        orderCancelDTO.setCurrentUserType(currentUserInfo.getUserType());
        orderCancelDTO.setCurrentUserId(currentUserInfo.getId());
        orderCancelDTO.setCurrentUserName(currentUserInfo.getName());
        Long orderId = orderCancelDTO.getId();
        // 通过状态机获取快照缓存
        String orderSnapshotJson = orderStateMachine.getCurrentSnapshotCache(orderCancelDTO.getId().toString());
        OrderSnapshotDTO orderSnapshotDTO = JsonUtils.toBean(orderSnapshotJson, OrderSnapshotDTO.class);
        if (ObjectUtils.isNull(orderSnapshotDTO)) {
            throw new CommonException("订单号为" + orderId + "的订单不存在");
        }
        Integer ordersStatus = orderSnapshotDTO.getOrdersStatus();
        if (ObjectUtils.equal(ordersStatus, OrderStatusEnum.NO_PAY.getStatus())) {
            owner.cancelByNoPay(orderCancelDTO);
        } else if (ObjectUtils.equal(ordersStatus, OrderStatusEnum.DISPATCHING.getStatus())) {
            BeanUtils.copyProperties(orderSnapshotDTO, orderCancelDTO);
            owner.cancelByDispatching(orderCancelDTO);
            owner.requestRefundNewThread(orderId);
        } else {
            throw new CommonException("当前订单状态不支持取消");
        }
    }


    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void cancelByNoPay(OrderCancelDTO orderCancelDTO) {
        // 新增取消记录
        owner.insertCancel(orderCancelDTO);
        String orderId = orderCancelDTO.getId().toString();
        // 通过状态机获取快照缓存
        String orderSnapshotJson = orderStateMachine.getCurrentSnapshotCache(orderCancelDTO.getId().toString());
        OrderSnapshotDTO orderSnapshotDTO = JsonUtils.toBean(orderSnapshotJson, OrderSnapshotDTO.class);
        // 更新快照状态
        orderSnapshotDTO.setUpdateTime(LocalDateTime.now());
        orderSnapshotDTO.setOrdersStatus(OrderStatusEnum.CANCELED.getStatus());
        // 通过状态机更新订单状态
        orderStateMachine.changeStatus(orderSnapshotDTO.getUserId(), orderId, OrderStatusChangeEventEnum.CANCEL, orderSnapshotDTO);
        // 优惠券回退
        if (orderSnapshotDTO.getDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            CouponUseBackReqDTO couponUseBackReqDTO = new CouponUseBackReqDTO();
            couponUseBackReqDTO.setOrdersId(orderCancelDTO.getId());
            couponUseBackReqDTO.setUserId(orderCancelDTO.getUserId());
            // 优惠券号由useBack方法自己取
            couponApi.useBack(couponUseBackReqDTO);
        }
    }

    @Override
    @GlobalTransactional
    public void cancelByDispatching(OrderCancelDTO orderCancelDTO) {
        // 新增取消记录
        owner.insertCancel(orderCancelDTO);
        // 更新快照状态
        OrderSnapshotDTO orderSnapshotDTO = new OrderSnapshotDTO();
        orderSnapshotDTO.setUpdateTime(LocalDateTime.now());
        orderSnapshotDTO.setOrdersStatus(OrderStatusEnum.CLOSED.getStatus());
        orderSnapshotDTO.setRefundStatus(RefundStatusEnum.SENDING.getCode());
        // 通过状态机更新订单状态
        orderStateMachine.changeStatus(orderSnapshotDTO.getUserId(), orderCancelDTO.getId().toString(), OrderStatusChangeEventEnum.CLOSE_DISPATCHING_ORDER, orderSnapshotDTO);
        // 添加退款记录
        OrdersRefund ordersRefund = new OrdersRefund();
        ordersRefund.setId(orderCancelDTO.getId());
        ordersRefund.setTradingOrderNo(orderCancelDTO.getTradingOrderNo());
        ordersRefund.setRealPayAmount(orderCancelDTO.getRealPayAmount());
        ordersRefundService.save(ordersRefund);
        // 优惠券回退
        if (orderSnapshotDTO.getDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            CouponUseBackReqDTO couponUseBackReqDTO = new CouponUseBackReqDTO();
            couponUseBackReqDTO.setOrdersId(orderCancelDTO.getId());
            couponUseBackReqDTO.setUserId(orderCancelDTO.getUserId());
            // 优惠券号由useBack方法自己取
            couponApi.useBack(couponUseBackReqDTO);
        }
    }

    @Override
    public void insertCancel(OrderCancelDTO orderCancelDTO) {
        OrdersCanceled ordersCanceled = new OrdersCanceled();
        ordersCanceled.setId(orderCancelDTO.getId());
        ordersCanceled.setCancellerId(orderCancelDTO.getCurrentUserId());
        ordersCanceled.setCancelerName(orderCancelDTO.getCurrentUserName());
        ordersCanceled.setCancellerType(orderCancelDTO.getCurrentUserType());
        ordersCanceled.setCancelReason(orderCancelDTO.getCancelReason());
        ordersCanceled.setCancelTime(LocalDateTime.now());
        ordersCanceledMapper.insert(ordersCanceled);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void requestRefundNewThread(Long orderId) {
        // 启动一个线程请求第三方退款接口
        new Thread(() -> {
            // 查询退款记录
            OrdersRefund ordersRefund = ordersRefundService.getById(orderId);
            if (ObjectUtil.isNotNull(ordersRefund)) {
                // 请求退款
                ordersHandler.requestRefundOrder(ordersRefund);
            }
        }).start();
    }

    @Override
    public PageResult<OperationOrdersDetailResDTO> queryPage(OrderPageQueryReqDTO orderPageQueryReqDTO) {
        return null;
    }

}
